#include "RELevelParser.h"

enum
{
	level_ID = 0,
	actor_ID,
	transform_ID,
		position_ID,
			position_X_ID,
			position_Y_ID,
			position_Z_ID,
		rotation_ID,
			rotation_X_ID,
			rotation_Y_ID,
			rotation_Z_ID,
		scale_ID,
			scale_X_ID,
			scale_Y_ID,
			scale_Z_ID,
	render_ID,
		mesh_ID,
			material_ID,
				ambient_ID,
					ambient_A_ID,
					ambient_R_ID,
					ambient_G_ID,
					ambient_B_ID,
				diffuse_ID,
					diffuse_A_ID,
					diffuse_R_ID,
					diffuse_G_ID,
					diffuse_B_ID,
				specular_ID,
					specular_A_ID,
					specular_R_ID,
					specular_G_ID,
					specular_B_ID,
				texture_ID
};

RELevelParser::RELevelParser()
{
	Stack.ptr_tosend = this;
	CallbackMap g_always, g_global, g_level, g_actor, g_transform_cmp, g_position, g_rotation, g_scale, g_render_cmp, g_mesh, g_material, g_texture, g_ambient, g_diffuse, g_specular;

	g_always["STACK_END"] = (void(*)(ParserStack*))&STACK_END;
	g_always["STACK_BEGIN"] = (void(*)(ParserStack*))&STACK_BEGIN;

	g_global["level"] = (void(*)(ParserStack*))&LEVEL;
	g_global["resource"] = (void(*)(ParserStack*))&RESOURCE_FILE;

	g_level["actor"] = (void(*)(ParserStack*))&ACTOR;

	g_actor["cmp"] = (void(*)(ParserStack*))&COMPONENT;

		g_transform_cmp["pos"] = (void(*)(ParserStack*))&POSITION;
			g_position["x"] = (void(*)(ParserStack*))&POSITION_X;
			g_position["y"] = (void(*)(ParserStack*))&POSITION_Y;
			g_position["z"] = (void(*)(ParserStack*))&POSITION_Z;
		g_transform_cmp["rot"] = (void(*)(ParserStack*))&ROTATION;
			g_rotation["x"] = (void(*)(ParserStack*))&ROTATION_X;
			g_rotation["y"] = (void(*)(ParserStack*))&ROTATION_Y;
			g_rotation["z"] = (void(*)(ParserStack*))&ROTATION_Z;
		g_transform_cmp["scl"] = (void(*)(ParserStack*))&SCALE;
			g_scale["x"] = (void(*)(ParserStack*))&SCALE_X;
			g_scale["y"] = (void(*)(ParserStack*))&SCALE_Y;
			g_scale["z"] = (void(*)(ParserStack*))&SCALE_Z;

		g_render_cmp["mesh"] = (void(*)(ParserStack*))&MESH;
		g_render_cmp["mtrl"] = (void(*)(ParserStack*))&MATERIAL;
			g_material["a"] = (void(*)(ParserStack*))&AMBIENT;
				g_ambient["a"] = (void(*)(ParserStack*))&AMBIENT_A;
				g_ambient["r"] = (void(*)(ParserStack*))&AMBIENT_R;
				g_ambient["g"] = (void(*)(ParserStack*))&AMBIENT_G;
				g_ambient["b"] = (void(*)(ParserStack*))&AMBIENT_B;
			g_material["d"] = (void(*)(ParserStack*))&DIFFUSE;
				g_diffuse["a"] = (void(*)(ParserStack*))&DIFFUSE_A;
				g_diffuse["r"] = (void(*)(ParserStack*))&DIFFUSE_R;
				g_diffuse["g"] = (void(*)(ParserStack*))&DIFFUSE_G;
				g_diffuse["b"] = (void(*)(ParserStack*))&DIFFUSE_B;
			g_material["s"] = (void(*)(ParserStack*))&SPECULAR;
				g_specular["a"] = (void(*)(ParserStack*))&SPECULAR_A;
				g_specular["r"] = (void(*)(ParserStack*))&SPECULAR_R;
				g_specular["g"] = (void(*)(ParserStack*))&SPECULAR_G;
				g_specular["b"] = (void(*)(ParserStack*))&SPECULAR_B;
				g_specular["p"] = (void(*)(ParserStack*))&SPECULAR_P;
			g_material["txtr"] = (void(*)(ParserStack*))&TEXTURE;



	Stack.m_StackMap[-2] = g_always;
	Stack.m_StackMap[-1] = g_global;
	Stack.m_StackMap[level_ID] = g_level;
	Stack.m_StackMap[actor_ID] = g_actor;
	Stack.m_StackMap[transform_ID] = g_transform_cmp;
		Stack.m_StackMap[position_ID] = g_position;
		Stack.m_StackMap[rotation_ID] = g_rotation;
		Stack.m_StackMap[scale_ID] = g_scale;
	Stack.m_StackMap[render_ID] = g_render_cmp;
		Stack.m_StackMap[mesh_ID] = g_mesh;
			Stack.m_StackMap[material_ID] = g_material;
				Stack.m_StackMap[ambient_ID] = g_ambient;
				Stack.m_StackMap[diffuse_ID] = g_diffuse;
				Stack.m_StackMap[specular_ID] = g_specular;
				Stack.m_StackMap[texture_ID] = g_texture;


}

AssetDataList & RELevelParser::VLoad(Resource & res, char * bfr, unsigned int sze )
{
	m_FileReadCallback.sze = sze;
	m_FileReadCallback.bfr = bfr;
	xml = irr::io::createIrrXMLReader(&m_FileReadCallback);
	std::string buffer;
	VBegin();
	while(xml && xml->read())
	{
		switch(xml->getNodeType())
		{
			case irr::io::EXN_ELEMENT:
				Stack.ProcessString(xml->getNodeName());
				Stack.ProcessString("STACK_BEGIN");
				break;
			case irr::io::EXN_ELEMENT_END:
				Stack.ProcessString("STACK_END");
				break;
			case irr::io::EXN_TEXT: // this is not needed. EXN_ELEMENT will take care of the text
				break;
		}
	}
	VEnd();
	delete xml;
	return VGetData();
}
AssetDataList & RELevelParser::VGetData()
{
	return m_AssetDataList;
}
void RELevelParser::VBegin()
{
}
void RELevelParser::VEnd()
{
}


void RELevelParser::RESOURCE_FILE(RELevelParser *instance)
{
	if(instance->xml->getAttributeValueSafe("file") != std::string())
	{
		if(instance->xml->getAttributeValueSafe("type") == std::string("no"))
		{
			REC()->VAddResourceFile(ResourceFilePtr(RE_NEW NoResourceFile(instance->xml->getAttributeValue("file"))));
		}else if (instance->xml->getAttributeValueSafe("type") == std::string("zip"))
		{
			REC()->VAddResourceFile(ResourceFilePtr(RE_NEW ResourceZipFile((TCHAR*)instance->xml->getAttributeValue("file"))));
		}else
		{
			assert(0 && "File type not found.");
		}
	}
}

void RELevelParser::LEVEL(RELevelParser* instance)
{
	instance->Stack.m_ToStack = level_ID;
	//now create the level(level is nothing more that list of actor data)
	instance->m_AssetDataList.push_back(AssetDataPtr(RE_NEW LevelData));
	instance->m_pAssetData = instance->m_AssetDataList.back();
	LevelData * const level = dynamic_cast<LevelData*>(instance->m_pAssetData.get());
	level->m_name = RE_String(instance->xml->getAttributeValue("name"));
}
void RELevelParser::STACK_END(RELevelParser* instance)
{
	instance->Stack.m_Stack.pop_back();
}
void RELevelParser::STACK_BEGIN(RELevelParser *instance)
{
	instance->Stack.m_Stack.push_back(instance->Stack.m_ToStack);
}
void RELevelParser::ACTOR(RELevelParser* instance)
{
	instance->Stack.m_ToStack = actor_ID;
	//create the actor
	AssetDataPtr actorptr(RE_NEW ActorData);
	//check if there is an level to attach
	if(instance->m_pAssetData->GetAssetType() == LevelData::m_LevelDataType)
	{
		instance->m_pAssetData->AddChild(actorptr);
		actorptr->SetParent(instance->m_pAssetData);
	}
	else if(instance->m_pAssetData->TraceParent(LevelData::m_LevelDataType) != AssetDataPtr())
	{
		instance->m_pAssetData->TraceParent(LevelData::m_LevelDataType)->AddChild(actorptr);
		actorptr->SetParent( instance->m_pAssetData->TraceParent(LevelData::m_LevelDataType) );
	}
	else
	{
		instance->m_AssetDataList.push_back(actorptr);
	}
	instance->m_pAssetData = actorptr;
	//ok it is ready.
	ActorData * const actor = dynamic_cast<ActorData*>(actorptr.get());
	actor->m_name = RE_String(instance->xml->getAttributeValue("name"));
}

void RELevelParser::COMPONENT(RELevelParser *instance)
{
	std::string type = instance->xml->getAttributeValue("type");
	if(type == "transform")
	{
		RELevelParser::TRANSFORM(instance);
	}else if(type == "render")
	{
		RELevelParser::RENDER(instance);
	}
}

void RELevelParser::TRANSFORM(RELevelParser *instance)
{
	instance->Stack.m_ToStack = transform_ID;
	AssetDataPtr transformptr(RE_NEW TransformData);
	//find a place to attach
	if(instance->m_pAssetData->GetAssetType() == ActorData::m_ActorDataType)
	{
		instance->m_pAssetData->AddChild(transformptr);
		transformptr->SetParent(instance->m_pAssetData);
	}
	else if(instance->m_pAssetData->TraceParent(ActorData::m_ActorDataType) != AssetDataPtr())// no it isn't, better trace the parent chaing until actor is found
	{
		instance->m_pAssetData->TraceParent(ActorData::m_ActorDataType)->AddChild(transformptr); // not really clever idea however I really don't have time
		transformptr->SetParent(instance->m_pAssetData);
	}else
	{
		instance->m_AssetDataList.push_back(transformptr);
	}
	instance->m_pAssetData = transformptr;
	TransformData * const transform = dynamic_cast<TransformData*>(transformptr.get());
	transform->m_name = RE_String("Transform");
}

void RELevelParser::POSITION(RELevelParser *instance)
{
	instance->Stack.m_ToStack = position_ID;
}

void RELevelParser::POSITION_X(RELevelParser *instance)
{
	TransformData * transform = dynamic_cast<TransformData*>(instance->m_pAssetData.get());
	instance->xml->read();
	transform->Position.x = atof(instance->xml->getNodeData());
}

void RELevelParser::POSITION_Y(RELevelParser *instance)
{
	TransformData * transform = dynamic_cast<TransformData*>(instance->m_pAssetData.get());
	instance->xml->read();
	transform->Position.y = atof(instance->xml->getNodeData());
}

void RELevelParser::POSITION_Z(RELevelParser *instance)
{
	TransformData * transform = dynamic_cast<TransformData*>(instance->m_pAssetData.get());
	instance->xml->read();
	transform->Position.z = atof(instance->xml->getNodeData());
}

void RELevelParser::ROTATION(RELevelParser *instance)
{
	instance->Stack.m_ToStack = rotation_ID;
}

void RELevelParser::ROTATION_X(RELevelParser *instance)
{
	TransformData * transform = dynamic_cast<TransformData*>(instance->m_pAssetData.get());
	instance->xml->read();
	transform->Rotation.x = atof(instance->xml->getNodeData());
}

void RELevelParser::ROTATION_Y(RELevelParser *instance)
{
	TransformData * transform = dynamic_cast<TransformData*>(instance->m_pAssetData.get());
	instance->xml->read();
	transform->Rotation.y = atof(instance->xml->getNodeData());
}

void RELevelParser::ROTATION_Z(RELevelParser *instance)
{
	TransformData * transform = dynamic_cast<TransformData*>(instance->m_pAssetData.get());
	instance->xml->read();
	transform->Rotation.z = atof(instance->xml->getNodeData());
}

void RELevelParser::SCALE(RELevelParser *instance)
{
	instance->Stack.m_ToStack = scale_ID;
}

void RELevelParser::SCALE_X(RELevelParser *instance)
{
	TransformData * transform = dynamic_cast<TransformData*>(instance->m_pAssetData.get());
	instance->xml->read();
	transform->Scale.x = atof(instance->xml->getNodeData());
}
void RELevelParser::SCALE_Y(RELevelParser *instance)
{
	TransformData * transform = dynamic_cast<TransformData*>(instance->m_pAssetData.get());
	instance->xml->read();
	transform->Scale.y = atof(instance->xml->getNodeData());
}
void RELevelParser::SCALE_Z(RELevelParser *instance)
{
	TransformData * transform = dynamic_cast<TransformData*>(instance->m_pAssetData.get());
	instance->xml->read();
	transform->Scale.z = atof(instance->xml->getNodeData());
}

void RELevelParser::RENDER(RELevelParser *instance)
{
	instance->Stack.m_ToStack = render_ID;
	AssetDataPtr renderptr(RE_NEW RenderData);
	//find a place to attach
	if(instance->m_pAssetData->GetAssetType() == ActorData::m_ActorDataType) // is working asset an actor?
	{
		instance->m_pAssetData->AddChild(renderptr);
		renderptr->SetParent(instance->m_pAssetData);
	}
	else if(instance->m_pAssetData->TraceParent(ActorData::m_ActorDataType) != AssetDataPtr())// no it isn't, better trace the parent chaing until actor is found
	{
		instance->m_pAssetData->TraceParent(ActorData::m_ActorDataType)->AddChild(renderptr);
		renderptr->SetParent(instance->m_pAssetData->TraceParent(ActorData::m_ActorDataType));
	}
	else // Couldn't find actor in the chain... just add it in the list, it may be used as a prefab later.
	{
		instance->m_AssetDataList.push_back(renderptr);
	}
	instance->m_pAssetData = renderptr;
	RenderData * const render = dynamic_cast<RenderData*>(renderptr.get());
	render->m_name = RE_String("Render");
}

void RELevelParser::MESH(RELevelParser *instance)
{
	instance->Stack.m_ToStack = mesh_ID;
	//check if there is name, if it doesn,t then bail
	if(instance->xml->getAttributeValueSafe("name") == "")
	{
		assert(0 && "The given REL file contain error/s. Mesh without name cannot exist.");
	}
	RE_String name = instance->xml->getAttributeValue("name");
	//check if there is source, and load it
	if(instance->xml->getAttributeValueSafe("source") != std::string())
	{
		REA()->GetAssetData(Resource(instance->xml->getAttributeValue("source")));
	}
	//now find the mesh data itself(it shoud be loaded if source given, or it may be loaded before
	AssetDataPtr asset = REA()->GetAssetData(name);
	if(asset == AssetDataPtr())
	{
		assert(0 && "The given REL file contain error/s. Mesh cannot exist without vertex data.");
	}
	RenderData * render = dynamic_cast<RenderData*>(instance->m_pAssetData.get());
	render->m_Mesh = asset;
}

void RELevelParser::MATERIAL(RELevelParser *instance)
{
	instance->Stack.m_ToStack = material_ID;
	AssetDataPtr asset; RenderData * render = NULL; RE_Material * mat = 0;
	RE_String name = "Material Default Name"; bool Allocate = true;
	//check if there is source.
	if(instance->xml->getAttributeValueSafe("source") != std::string())
	{
		//now load it if need;
		REA()->GetAssetData(Resource(instance->xml->getAttributeValue("source")));
	}
	//check if there is name
	if(instance->xml->getAttributeValueSafe("name") != std::string())
	{
		//check if this is parsed already
		asset = REA()->GetAssetData(instance->xml->getAttributeValue("name"));
		if(asset != AssetDataPtr())
		{
			Allocate = false;
		}
		name = RE_String(instance->xml->getAttributeValue("name"));
	}
	render = dynamic_cast<RenderData*>(instance->m_pAssetData.get());
	if(Allocate == true)
	{
		asset = AssetDataPtr(RE_NEW RE_Material);
	}
	render->m_pMaterial = asset;
	mat = dynamic_cast<RE_Material*>(asset.get());
	mat->m_name = name;
}


void RELevelParser::AMBIENT(RELevelParser *instance)
{
	instance->Stack.m_ToStack = ambient_ID;
}

void RELevelParser::AMBIENT_A(RELevelParser *instance)
{
	RenderData * render = NULL; RE_Material * mat = 0;
	render = dynamic_cast<RenderData*>(instance->m_pAssetData.get());
	mat = dynamic_cast<RE_Material*>(render->m_pMaterial.get());
	instance->xml->read();
	mat->m_Ambient.w = atof(instance->xml->getNodeData());
}
void RELevelParser::AMBIENT_R(RELevelParser *instance)
{
	RenderData * render = NULL; RE_Material * mat = 0;
	render = dynamic_cast<RenderData*>(instance->m_pAssetData.get());
	mat = dynamic_cast<RE_Material*>(render->m_pMaterial.get());
	instance->xml->read();
	mat->m_Ambient.x = atof(instance->xml->getNodeData());
}
void RELevelParser::AMBIENT_G(RELevelParser *instance)
{
	RenderData * render = NULL; RE_Material * mat = 0;
	render = dynamic_cast<RenderData*>(instance->m_pAssetData.get());
	mat = dynamic_cast<RE_Material*>(render->m_pMaterial.get());
	instance->xml->read();
	mat->m_Ambient.y = atof(instance->xml->getNodeData());
}
void RELevelParser::AMBIENT_B(RELevelParser *instance)
{
	RenderData * render = NULL; RE_Material * mat = 0;
	render = dynamic_cast<RenderData*>(instance->m_pAssetData.get());
	mat = dynamic_cast<RE_Material*>(render->m_pMaterial.get());
	instance->xml->read();
	mat->m_Ambient.z = atof(instance->xml->getNodeData());
}
void RELevelParser::DIFFUSE(RELevelParser *instance)
{
	instance->Stack.m_ToStack = diffuse_ID;
}
void RELevelParser::DIFFUSE_A(RELevelParser *instance)
{
	RenderData * render = NULL; RE_Material * mat = 0;
	render = dynamic_cast<RenderData*>(instance->m_pAssetData.get());
	mat = dynamic_cast<RE_Material*>(render->m_pMaterial.get());
	instance->xml->read();
	mat->m_Diffuse.w = atof(instance->xml->getNodeData());
}
void RELevelParser::DIFFUSE_R(RELevelParser *instance)
{
	RenderData * render = NULL; RE_Material * mat = 0;
	render = dynamic_cast<RenderData*>(instance->m_pAssetData.get());
	mat = dynamic_cast<RE_Material*>(render->m_pMaterial.get());
	instance->xml->read();
	mat->m_Diffuse.x = atof(instance->xml->getNodeData());
}
void RELevelParser::DIFFUSE_G(RELevelParser *instance)
{
	RenderData * render = NULL; RE_Material * mat = 0;
	render = dynamic_cast<RenderData*>(instance->m_pAssetData.get());
	mat = dynamic_cast<RE_Material*>(render->m_pMaterial.get());
	instance->xml->read();
	mat->m_Diffuse.y = atof(instance->xml->getNodeData());
}
void RELevelParser::DIFFUSE_B(RELevelParser *instance)
{
	RenderData * render = NULL; RE_Material * mat = 0;
	render = dynamic_cast<RenderData*>(instance->m_pAssetData.get());
	mat = dynamic_cast<RE_Material*>(render->m_pMaterial.get());
	instance->xml->read();
	mat->m_Diffuse.z = atof(instance->xml->getNodeData());
}
void RELevelParser::SPECULAR(RELevelParser *instance)
{
	instance->Stack.m_ToStack = specular_ID;
}
void RELevelParser::SPECULAR_A(RELevelParser *instance)
{
	RenderData * render = NULL; RE_Material * mat = 0;
	render = dynamic_cast<RenderData*>(instance->m_pAssetData.get());
	mat = dynamic_cast<RE_Material*>(render->m_pMaterial.get());
	instance->xml->read();
	mat->m_Specular.w = atof(instance->xml->getNodeData());
}
void RELevelParser::SPECULAR_R(RELevelParser *instance)
{
	RenderData * render = NULL; RE_Material * mat = 0;
	render = dynamic_cast<RenderData*>(instance->m_pAssetData.get());
	mat = dynamic_cast<RE_Material*>(render->m_pMaterial.get());
	instance->xml->read();
	mat->m_Specular.x = atof(instance->xml->getNodeData());
}
void RELevelParser::SPECULAR_G(RELevelParser *instance)
{
	RenderData * render = NULL; RE_Material * mat = 0;
	render = dynamic_cast<RenderData*>(instance->m_pAssetData.get());
	mat = dynamic_cast<RE_Material*>(render->m_pMaterial.get());
	instance->xml->read();
	mat->m_Specular.y = atof(instance->xml->getNodeData());
}
void RELevelParser::SPECULAR_B(RELevelParser *instance)
{
	RenderData * render = NULL; RE_Material * mat = 0;
	render = dynamic_cast<RenderData*>(instance->m_pAssetData.get());
	mat = dynamic_cast<RE_Material*>(render->m_pMaterial.get());
	instance->xml->read();
	mat->m_Specular.z = atof(instance->xml->getNodeData());
}
void RELevelParser::SPECULAR_P(RELevelParser *instance)
{
	RenderData * render = NULL; RE_Material * mat = 0;
	render = dynamic_cast<RenderData*>(instance->m_pAssetData.get());
	mat = dynamic_cast<RE_Material*>(render->m_pMaterial.get());
	instance->xml->read();
	mat->m_SpecularPower = atof(instance->xml->getNodeData());
}
void RELevelParser::TEXTURE(RELevelParser *instance)
{
	instance->Stack.m_ToStack = texture_ID;
	AssetDataPtr asset; RenderData * render = NULL; RE_Mesh * mesh = NULL; RE_Material * mat = 0;
	//check if there is source.
	if(instance->xml->getAttributeValueSafe("source") != std::string())
	{
		//now load it if need;
		REA()->GetAssetData(Resource(instance->xml->getAttributeValue("source")));
	}
	//check if there is name
	if(instance->xml->getAttributeValueSafe("name") != std::string())
	{
		//check if this is parsed already
		asset = REA()->GetAssetData(instance->xml->getAttributeValue("name"));
		if(asset == AssetDataPtr())
		{
			assert(0 && "Error in REL file. Texture without bitmap data.");
		}
	}else
	{
		assert(0 && "Error in REL file. Texture without name!");
	}
	render = dynamic_cast<RenderData*>(instance->m_pAssetData.get());
	mat = dynamic_cast<RE_Material*>(render->m_pMaterial.get());
	mat->m_Texture = asset;
}